package com.wang.designpattern.singleton;

import org.apache.commons.lang3.SerializationUtils;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 静态内部类懒汉式单例模式
 */
class Singleton05Test {

    public static void main(String[] args) {
        MyThread5 mt1 = new MyThread5("线程A ") ;    // 实例化对象
        MyThread5 mt2 = new MyThread5("线程B ") ;    // 实例化对象
        Thread t1 = new Thread(mt1) ;       // 实例化Thread类对象
        Thread t2 = new Thread(mt2) ;       // 实例化Thread类对象
        t1.start() ;    // 启动多线程
        t2.start() ;    // 启动多线程
        try {
            // 通过反射攻击单例模式
            Constructor<Singleton05> constructor = Singleton05.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            Singleton05 newInstance = constructor.newInstance();
            System.out.println("反射 newInstance : " + newInstance.hashCode());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        // 通过反序列化攻击单例模式
        Singleton05 instance = Singleton05.getInstance();
        byte[] serialize = SerializationUtils.serialize(instance);
        Singleton05 newInstance = SerializationUtils.deserialize(serialize);
        System.out.println("反序列化 instance : " + instance.hashCode());
        System.out.println("反序列化 newInstance : " + newInstance.hashCode());
    }
}

class Singleton05 implements Serializable {

    private Singleton05() {}

    private static class Singleton05Holder {
        private static Singleton05 instance = new Singleton05();
    }

    public static Singleton05 getInstance() {
        return Singleton05Holder.instance;
    }
}

class MyThread5 implements Runnable{ // 实现Runnable接口，作为线程的实现类
    private String name ;       // 表示线程的名称
    public MyThread5(String name){
        this.name = name ;      // 通过构造方法配置name属性
    }
    public void run(){  // 覆写run()方法，作为线程 的操作主体、
        if (name.equals("线程A ")) {
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Singleton05 singleton = Singleton05.getInstance();
        System.out.println(name +  " " + singleton.hashCode());
    }
}